export const isObject = something => `${something}` === '[object Object]'
export const isArray = something => something instanceof Array
export const isString = some => typeof some === 'string'

export function removeNullValue(some) {
  if (isObject(some)) {
    return Object.keys(some).reduce(
      (o, k) => ({
        ...o,
        [k]: removeNullValue(some[k])
      }),
      {}
    )
  } else if (isArray(some)) {
    return some.map(t => removeNullValue(t))
  } else if (some === null || some === 'null') {
    return ''
  }

  return some
}

export function pick(setting) {
  function typeConvert(value, typeString) {
    if (!typeString) return value
    switch (typeString.trim().toLowerCase()) {
      case 'float':
        return parseFloat(value)
      case 'int':
        return parseInt(value, 10)
      default:
        return value
    }
  }

  function deepProp(object, string) {
    const [propKey, propType, ...propTypeParams] = string.split(',')
    const props = propKey.trim().split('.')
    const value = props.reduce(
      (o, key) => (o && isObject(o) ? o[key] : o),
      object
    )
    return {
      key: props[props.length - 1],
      value: typeConvert(value, propType, ...propTypeParams)
    }
  }

  function pickArray(array) {
    return function pickArrayFunc(object) {
      return array.reduce((o, k) => {
        const { key, value } = deepProp(object, k)
        return { ...o, [key]: value }
      }, {})
    }
  }

  function pickObject(objectSetting) {
    return function pickObjectFunc(object) {
      return Object.keys(objectSetting).reduce((o, k) => {
        const { value } = deepProp(object, objectSetting[k])
        return { ...o, [k]: value }
      }, {})
    }
  }

  if (isArray(setting)) {
    return pickArray(setting)
  } else if (isObject(setting)) {
    return pickObject(setting)
  } else if (isString(setting)) {
    return obj => deepProp(obj, setting).value
  }

  throw new Error('参数必须为对象或数组')
}

export function reduce(o, f) {
  return Object.keys(o).reduce((obj, key) => {
    const value = f(key, o[key], o)
    if (value) o[key] = value
    return o
  }, {})
}

export function isIos() {
  const ua = window.navigator.userAgent
  return ua.match(/iPhone|iPad/i)
}

export const promiseWrap = f => options => {
  const newOptions = { ...options }
  delete newOptions.success
  delete newOptions.fail
  return new Promise((resolve, reject) =>
    f({
      ...newOptions,
      success: resolve,
      fail: reject
    })
  )
}

export function cloneDeep(a) {
  if (isObject(a)) {
    return Object.keys(a).reduce((o, k) => ({ ...o, [k]: cloneDeep(a[k]) }), {})
  } else if (isArray(a)) {
    return a.map(t => cloneDeep(t))
  }
  return a
}

export function findItemByValue(valueList, addressData) {
  const itemList = []
  let data = addressData

  while (valueList && valueList.length && data) {
    const value = valueList.shift()
    for (let i = 0; i < data.length; i += 1) {
      const t = data[i]
      if (t.value === value) {
        itemList.push(t)
        data = t.children
        break
      }
    }
  }

  return itemList
}

export function findItemByName(nameList, addressData) {
  function find(nl, list, result) {
    if (!nl || nl.length === 0) return result
    const head = nl.shift()
    const target = list.find(t => t.name === head)

    if (!target) {
      return result
    }

    result.push(target)
    if (target.children) {
      return find(nl, target.children, result)
    }

    return result
  }

  const codeList = find(nameList, addressData, [])
  return codeList
}

export function range(from, to, step = 1) {
  const r = (s, e, a) => {
    const next = s + step
    if (next === s) throw new Error('step can not be zero')
    if (
      (s <= e && next <= e && step < 0) ||
      (s >= e && next >= e && step > 0)
    ) {
      return a
    }
    if ((s < e && next >= e && step > 0) || (s > e && next <= e && step < 0)) {
      a.push(s)
      return a
    }
    a.push(s)
    return r(next, e, a)
  }
  return r(from, to, [])
}
